/**
 * @file qstore.js
 */
;(function(qStore){

var ArrayUtil = {
    rest : function(list) {
        return this.toArray(list, 1);
    },

    first : function(list) {
        return  list && list[0];
    },

    toArray : function(list, start) {
        return list && ([].slice.call(list, start || 0));
    }
};

var stringifyParam = function(plist) {
    var params = [];

    for (var i = 0, len = plist.length; i < len; i++) {
        params.push(
            $.type(plist[i]) == 'object' ?
            JSON.stringify(plist[i]) : plist[i]
        );
    }

    return params;
};

/**
 * 客户端接口调用
 */
qStore.cmd = function(action) {
    var params = stringifyParam(ArrayUtil.rest(arguments));

    if (window.AndroidWebview && AndroidWebview[action]) {
        return AndroidWebview[action].apply(AndroidWebview, params);
    } else {
        window.console && console.log(action + ':' + [].join.call(params, '|'));
    }
};

// 挂载辅助工具
qStore.lib = {}; 

qStore.lib.ArrayUtil = ArrayUtil;

})(window.qStore || (window.qStore = {}));

/**
 * @file: 提供onReady事件机制
 */
(function(lib){

var Delay = lib.Delay = function() {
    this.deferred = $.Deferred();
    this.promise = this.deferred.promise();
    this.fired = false;
};

$.extend(Delay.prototype, {
    fireReady : function() {
        if (this.fired) return;
        
        this.deferred.resolve.apply(this.deferred, arguments);
        this.fired = true;
    },

    ready : function(fn) {
        this.promise.then(fn);
    }
});

})(qStore.lib);
/**
 * @file 一些常用工具函数
 *
 */
;(function(util, qStore){

var generateMID = function() {
    var doc = document, 
        nav = navigator,
        screen = window.screen,
        domain = doc.domain.toLowerCase(),
        ua = nav.userAgent.toLowerCase();

    function hash(s) {
        var h = 0, 
            g = 0,
            i = s.length - 1;
        for(i; i>= 0; i--) {
            var code = parseInt(s.charCodeAt(i), 10);
            h = ((h << 6) & 0xfffffff) + code + (code << 14);
            if ((g = h & 0xfe00000) != 0) {
                h = (h ^ (g >> 21));
            }
        }
        return h;
    }

    function guid() {
        var s = [
            nav.appName, nav.version, nav.language || nav.browserLanguage, 
            nav.platform, nav.userAgent, screen.width, 'x', screen.height, 
            screen.colorDepth, doc.referrer
        ].join(""), sLen = s.length, hLen = window.history.length;

        while (hLen) {
            s += (hLen--) ^ (sLen++);
        }

        return (Math.round(Math.random() * 2147483647) ^ hash(s)) * 2147483647;
    }

    var id;
    id = [hash(doc.domain), guid(), +new Date + Math.random() + Math.random()].join('');
    id = id.replace(/\./ig, 'e');
    id = id.substr(0, 32);
    
    return id;
};

var getFakeMID = function() {
    var fkmid = util.getLocalData('__m2__');
    if (fkmid) {
        return fkmid;
    }

    fkmid = generateMID();
    util.setLocalData('__m2__', fkmid);

    return fkmid;
};

/**
 * 获取客户端信息
 *
 * @return {json}
 */
util.getClientInfo = function() {
    var ci = qStore.cmd('getClientInfo') || {};
    /*
     * {"os":19,"pkgName":"com.qihoo.appstore","netType":1,
     * "soVersion":100,"imei":"5284047f4ffb4e04824a2fd1d1f0cd62",
     * "ui_nmode":0,"ui_version":"green","m2":"7ae57c3581127c5563cc3e8d2477a8ce",
     * "m":"5284047f4ffb4e04824a2fd1d1f0cd62","channel":"300001",
     * "supportSilentPush":true,"toid":"2188579259","version":"300050140"}
     */
    if (typeof ci == 'string') {
        ci = JSON.parse(ci);
    }

    return ci;
};

util.getQuery = (function() {
    var query = window.location.search.substr(1);
    var parts = query.split('&');
    var queryObj = {}; // url参数

    for (var i = 0, len = parts.length; i < len; i++) {
        var kv = parts[i].split('='), value;

        try {
            value = decodeURIComponent(kv[1]);
        } catch(e){
            value = kv[1];
        }

        queryObj[kv[0]] = value;
    }
    
    return function(key) {
        if (typeof key == 'undefined') {
            return queryObj;
        }
        
        return queryObj[key];
    };
})();

util.getMID = function() {
    return this.getQuery('m2') || this.getClientInfo().m2 || getFakeMID();
};

/**
 * 弹出toast消息
 *
 * @return null
 */
util.showMessage = function(message) {
    if (window.AndroidWebview) {
        qStore.cmd('showMessage', message);
    } else {
        // todo: UI模拟toast
        window.console && console.log(message);
    }
};

util.openUrl = function(url) {
    qStore.cmd('openPage', url);
};

util.getAppStatus = function(pkgid) {
    return qStore.app.getStatus(pkgid);
};

// 格式化字符串
// format("hello, %s", 'world'); -> 'hello, world';
util.format = function(s) {
    var index = 1, args = arguments;
    
    return String(s).replace(/%s/g, function(){ return args[index++]; });
};

util.getProtocol = function() {
    return location.protocol == 'https:' ? 'https:' : 'http:';
};

util.cmd = qStore.cmd;
util.log = util.showMessage;

})(qStore.util = {}, qStore);

/**
 * @file 运行环境检测
 *
 */
;(function(qStore){

var env = {}; // 运行环境信息
var userAgent = navigator.userAgent;

env.is_weixin = /MicroMessenger/i.test(userAgent);
env.is_iphone = /(iPhone|ipod|ipad|ios)/i.test(userAgent);
env.is_android = /Android/i.test(userAgent);
env.is_mobile = env.is_android || env.is_iphone || /Mobile/i.test(userAgent);
env.is_pc = !env.is_mobile;
env.is_zhushou = /360appstore/i.test(userAgent);

var qStoreDelay = new qStore.lib.Delay();
qStore.ready = function(fn) {
    return qStoreDelay.ready(fn);
};

// 设置网络状况
qStore.ready(function(){
    if (!env.is_zhushou) {
        return;
    }

    var ci = qStore.util.getClientInfo();

    /*
     * GiveMe5/Libraries/QihooUtilsLib/src/com/qihoo/utils/net/NetConsts.java
     *
     * public class NetType {
     *     public static final int NET_TYPE_WIFI = 1;
     *     public static final int NET_TYPE_WAP = 2;
     *     public static final int NET_TYPE_NET = 3;
     * }
     *
     * public static final int NET_TYPE_NO_CONNECTION = -1;
     * public static final int NET_TYPE_WIFI = 1;
     * public static final int NET_TYPE_MOBILE_3G_WAP = 2;
     * public static final int NET_TYPE_MOBILE_3G_NET = 3;
     * public static final int NET_TYPE_MOBILE_2G_WAP = 4;
     * public static final int NET_TYPE_MOBILE_2G_NET = 5;
     * public static final int NET_TYPE_DEFAULT = 6;
     * public static final int NET_TYPE_MOBILE_4G = 7;
     *
     */
    env.network = ({
        '1' : 'wifi',
        '2' : 'wap', '4' : 'wap',
        '3' : 'net', '5' : 'net',
        '7' : '4g',
        '-1' : 'no-connect'
    })[ci.netType] || '';

    env.networkType = ci.netType;

    qStore.cmd('pageFinish');
});

// 检测Chrome是否打开了开发者工具
// console.log(domEl) 会访问domEl的id属性
// http://stackoverflow.com/questions/7798748/find-out-whether-chrome-console-is-open
var img = new Image;
var chromeDevToolsIsOpen = false;
img.__defineGetter__ && img.__defineGetter__('id', function(){
    chromeDevToolsIsOpen = true;
});

window.console && console.log(img);
img = null;

// 127检测
(function(){
    
if (!env.is_zhushou && env.is_mobile) {
    // 微信调试环境仍然检测127
    if (chromeDevToolsIsOpen && !env.is_weixin) {
        return;
    }

    /**
    * {
    *     "verCode":300050155,
    *     "server_version":1,
    *     "m2":"319c5e8d85585c5f098f5d597374504d",
    *     "channel":"600000","
    *     OS_version":22,
    *     "shake":true
    * }
    */
    var chkTimes = 0;
    (function chk127(){
        if (chkTimes++ > 10) return;

        $.ajax({
            url : 'http://i.qstore.org:38517/getClientInfo?_=' + (new Date).getTime(),
            dataType : 'jsonp',
            success : function(res) {
                env.isRPCWorking = true;
                env._127_clientInfo = res;
            },
            error : function() {
                setTimeout(chk127, 200);
            }
        });

    })();
}

})();

// todo: 客户端增加这个回调
window.AndroidWebview_clientReady = function(){
    env.is_zhushou = true;
    
    qStoreDelay.fireReady();
};

// 循环检测
var checkStart = (new Date).getTime();
(function() {
    if (window.AndroidWebview && AndroidWebview.getClientInfo) {
        env.is_zhushou = true;

        return qStoreDelay.fireReady();
    }

    if ((new Date).getTime() - checkStart > 2000) {
        return qStoreDelay.fireReady();
    }

    setTimeout(arguments.callee, 30);
})();

qStore.env = env;

})(window.qStore);

/**
 * @file 特性检测
 *
 * 某些功能只能根据版本号进行检测
 */
;(function(qStore){

var clientInfo = null;
var clientVersion = 0;

var support = qStore.support = {
    init : function() {
        clientInfo = qStore.util.getClientInfo();
        clientVersion = clientInfo.version;
    },

    pause : function() {
        return clientVersion >= 111000102;
    }
};

qStore.ready(support.init);

})(window.qStore);
/**
 * @file 本地数据存储
 * 
 * 【注意】如果存储的字符串中含有html标签，可能会导致客户端失去响应
 * 大段html字符串，请自行调用localStorage进行存储
 */
(function(util, qStore) {
    // 某些机型可能不支持localStorage, 比如早期的三星
    var localStorageAvailable = (function(){
        try { 
            // 禁止本地存储后，直接访问localStorage会报错
            return !!window.localStorage; 
        } catch(e) {
            return false;
        }
    })();

    var setLocalData = function(key, value) {
        if (arguments.length < 2) {return;}

        var data = JSON.stringify({
            __type__ : 'qstore-data',
            __value__ : value
        });
        
        if (localStorageAvailable) {
            localStorage.setItem(key, data);
        }
        else if (window.AndroidWebview) {
            qStore.cmd('saveData', key, data);
        }
    };

    var getLocalData = function(key) {
        var data = "";

        if (localStorageAvailable) {
            data = localStorage.getItem(key);
        }
        else if (window.AndroidWebview) {
            data = qStore.cmd('getData', key, '');
        }

        try {
            data = JSON.parse(data);

            if (data.__type__ && data.__type__ == 'qstore-data') {
                return data.__value__;
            }

            return data;
        } catch(e) {
            return data;
        }
    };


    /**
     * 设置本地数据
     *
     * @param {string} key
     * @param {any} value, 任意类型
     *
     */
    util.setLocalData = function(key, value) {
        return setLocalData(key, value);
    };

    /**
     * 获取本地数据
     *
     * @param {string} key
     *
     * @return {any} 任意类型
     */
    util.getLocalData = function(key) {
        if (typeof key == 'undefined') {
            return;
        }

        return getLocalData(key);
    };

    /**
     * 清除本地数据
     *
     * @param {string} key
     */
    util.delLocalData = function(key) {
        if (key) {
            if (localStorageAvailable) {
                localStorage.removeItem(key);
            }
            
            if (window.AndroidWebview) {
                qStore.cmd('saveData', key, '');
            }   
        }
    };

})(qStore.util, window.qStore);

/**
 * @file cookie处理
 */
;(function(util){
    
var cookie = function(key, value, options) {
    var days, time, result, decode;

    // 设置cookie
    if (arguments.length > 1 && String(value) !== "[object Object]") {
        // Enforce object
        options = options || {};

        if (value === null || value === undefined) options.expires = -1;

        if (typeof options.expires === 'number') {
            days = (options.expires * 24 * 60 * 60 * 1000);
            time = options.expires = new Date();

            time.setTime(time.getTime() + days);
        }
        // 精确时间
        else if (typeof options.expiresAt) {
            options.expires = options.expiresAt;
        }

        value = String(value);
        options.path = options.path || '/';
        options.domain = options.domain || document.domain;
        
        return (document.cookie = [
            encodeURIComponent(key), '=',
            options.raw ? value : encodeURIComponent(value),
            options.expires ? '; expires=' + options.expires.toUTCString() : '',
            options.path ? '; path=' + options.path : '',
            options.domain ? '; domain=' + options.domain : '',
            options.secure ? '; secure' : ''
        ].join(''));
    }

    // Key and possibly options given, get cookie
    options = value || {};

    decode = options.raw ? function(s) { return s; } : decodeURIComponent;

    return (
        (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ?
        decode(result[1]) : null
    );
};

util.setCookie = function(key, value, options) {
    if ($.type(options) == 'number') {
        options = {
            expires : options
        };
    }

    return cookie(key, value, options);
};

util.getCookie = function(key) {
    return cookie(key);
};

util.delCookie = function(key) {
    return cookie(key, null);
};

})(qStore.util);
/**
 * @file pos打点
 *
 */
(function(util){

var queue = []; // 请求队列
var isLoading = false;
var Logger = {

    /**
     * 获取当前页面URL
     * @return {string}
     */
    getPageHref : function() {
        return location.protocol + '//' + location.host + location.pathname;
    },
    
    getRefer : function() {
        return util.getQuery('refer');
    },
    
    /**
     * 获取统计URL
     *
     * @param {string} sid, 软件ID
     * @param {string} act, start=下载，show=pv打点  browse=点击打点
     * @param {string} pos, 位置
     */
    getLogUrl : function(sid, act, pos, data) {
        var defaultParam = {
            u : this.getPageHref(),
            ver : '',
            mid : util.getQuery('m') || util.getMID(),
            cid : '',
            from : '',
            market_id : '360market',
            tj : '',
            refer : ''
        };

        var mainParam = {
            sid : sid || '',
            act : act || '',
            pos : pos || '',
            _ : (new Date).getTime()
        };

        var paramObj = {};
        paramObj = $.extend(paramObj, defaultParam);
        paramObj = $.extend(paramObj, data || {});
        paramObj = $.extend(paramObj, mainParam);

        var server = 'http://s.360.cn/zhushou/soft.html';

        return server + '?' + $.param(paramObj);
    },

    request : function(url) {
        if (!this.hamal) {
            var hamal = this.hamal = document.createElement('img');

            hamal.style.visibility = 'hidden';
            hamal.style.width = hamal.style.height = '1px';
            hamal.style.position = 'absolute';
            hamal.style.left = '-1000px';
            document.body.appendChild(hamal);
            
            hamal.onload = hamal.onerror = function() {
                isLoading = false;
                if (queue.length > 0) {
                    Logger.request(queue.shift());
                }
            };
        }
        
        if (isLoading) {
            queue.push(url);
            return;
        }
        isLoading = true;
        this.hamal.src = url;
    },

    record : function() {
        var logUrl = this.getLogUrl.apply(this, arguments);

        this.request(logUrl);
    }
};

util.record = function() {
    return Logger.record.apply(Logger, arguments);
};

})(qStore.util);
/**
 * @file 360账号登录功能
 * 
 */
;(function(util){

window.QSTORE_EVENT_LOGIN_CHANGE = 'qstore-login-change';
window.QSTORE_EVENT_LOGIN = 'qstore-try-login';

// 设定客户端登录回调
// onLoginChanged 客户端回调时机很早，有可能在AndroidWebview就绪前就调用了
// 因此需要在ready后才fire事件，否则会导致用户信息获取失败(通过调用客户端接口获取)，并且影响AndroidWebview的后续注入
// 其他客户端端回调也需要注意这个问题
var old_onLoginChanged = window.onLoginChanged;
window.onLoginChanged = function(data) {
    qStore.ready(function(){
        old_onLoginChanged && old_onLoginChanged(data);
        qStore.trigger(QSTORE_EVENT_LOGIN_CHANGE, [data]);
    });
};

/**
 * 判断是否处于登录状态
 *
 * @return {boolean} true|false
 */
util.hasLogin = function() {
    return !!qStore.util.getCookie('Q');
};

/**
 * 登录，不一定会登录成功
 *
 * @param {function} callback, 回调函数
 * 
 * @return {Promise}
 */
util.tryLogin = function(callback) {
    if (this.hasLogin()) {
        return this.getUserInfo(callback);
    }

    // 进行客户端登录
    if (qStore.env.is_zhushou) {
        var deferred = $.Deferred();
        var promise = deferred.promise();
        var _this = this;

        qStore.one(QSTORE_EVENT_LOGIN, function(evt, data){
            if (data) {
                _this.getUserInfo(function(userInfo){
                    callback && callback(userInfo);
                    deferred.resolve(userInfo);
                });
            } else {
                callback && callback(false);
                deferred.reject(false);
            }
        });

        // 老版本客户端可能不会调用 onLoginChanged
        // 因此我们在页面聚焦时重新检测一下登录状态
        qStore.one(QSTORE_EVENT_ACTIVITY_RESUME, function(evt){
            setTimeout(function(){
                qStore.trigger(QSTORE_EVENT_LOGIN, [util.hasLogin()]);
            }, 10);
        });

        // 打开登录界面
        qStore.cmd('tryLogin', 'noop');

        return promise;
    }

    // 跳转至web登录界面
    window.location = 'http://i.360.cn/login/wap?destUrl=' + encodeURIComponent(location.href);
};

/**
 * 获取用户信息,异步处理函数
 * 
 * @param {function} callback, 回调函数
 *
 * @return {Promise} 
 */
util.getUserInfo = function(callback) {
    var deferred = $.Deferred();
    var promise = deferred.promise();

    var resolveOrReject = function(data) {
        callback && callback(data);

        if (data) {
            deferred.resolve(data);
        } else {
            deferred.reject(data);
        }

        return promise;
    };

    if (!this.hasLogin()) {
        return resolveOrReject(false);
    }
    
    // 调用客户端端接口获取用户信息
    if (qStore.env.is_zhushou) {
        // {
        //  "qid":"130165900",
        //  "avatar":"http://quc.qhimg.com/dm/150_150_100/t01a27bfbe84e89121a.jpg",
        //  "isDefaltAvatar":false,
        //  "name":"Naicy.W"
        // }
        var user = JSON.parse(qStore.cmd('getCurrentUserInfo') || '{}');
        if (user.avatar) {
            return resolveOrReject(user);
        }
    }

    // 如果失败，则通过web api获取用户信息
    // todo: 跟用户中心要一个信息全面一点的接口
    $.ajax({
        url : 'http://js.login.360.cn/?o=sso&m=info&time=' + (new Date).getTime(),
        jsonpCallback : 'func',
        dataType : 'jsonp',
        success : function(res) {
            res.name = res.nickname || res.userName || res.username;
            res.avatar = res.img_url;

            resolveOrReject(res);
        },

        error : function() {
            resolveOrReject(false);
        }
    });

    return promise;
};

})(qStore.util);
/**
 * @file 提供下载流程、下载按钮自定义功能
 *
 */
;(function(qStore){

var plugin = {};

/**
 * 获取按钮文案
 * @public 

 * @param {string} action, ['open'|'download'|'resume'|'waiting'|'update']
 * @param {object} data = {apkid : 'com.qihoo', version : '0', status : 'download', progress : 10 }
 *
 * @return {string}
 */
plugin.getButtonLabel = function(action, data) {
    return '';
};

/**
 * 获取下载按钮HTML
 * @public
 *
 * @param {string} action, ['open'|'download'|'resume']
 * @param {object} data = {apkid : 'com.qihoo', version : '0', status : 'download', progress : 10 }
 *
 * @return {string}
 */
plugin.getButtonHTML = function(action, data) {
    return '';
};

/**
 * 修改下载参数
 * 
 * @public
 *
 * @return {object}
 *
 * 注: 如果返回的不是一个object，则视为无效值，系统会使用原有值
 */
plugin.getAppData = function(app) {
    return app;
};

/**
 * 是否可下载
 * 
 * @public
 * @param {object} app 应用信息
 *
 * @return {boolean|number}
 *   false: 禁止下载
 *   true | undefined: 可以下载
 *   number: 延迟number毫秒下载
 *
 */
plugin.downloadable = function(app) {
    return true;
};

/**
 * 是否可打开
 *
 * @return {boolean|number} 
 *  false : 禁止打开
 *  true|undefined : 可打开
 *  number: 延迟number毫秒打开
 */
plugin.openable = function(app) {
    return true;
};

qStore.getDownloadPlugin = function() {
    return plugin;
};

})(window.qStore);

/**
 * @file 自定义事件
 * 
 * 封装了一些客户端的特殊事件
 */
;(function(event, qStore){
    
window.QSTORE_EVENT_ACTIVITY_RESUME = 'activity-resume';
window.QSTORE_EVENT_ACTIVITY_CLOSE = 'activity-close';
window.QSTORE_EVENT_ACTIVITY_PAUSE = 'activity-pause';

// zepto 只支持dom对象的trigger事件
var $evtEntity = window.Zepto ? Zepto('<div></div>') : jQuery({});

// 客户端回调: activity被激活
window.AndroidWebview_onResume = function() {
    $evtEntity.trigger(QSTORE_EVENT_ACTIVITY_RESUME);
};

// 客户端回调：页面失焦时
window.AndroidWebview_onPause = function() {
    $evtEntity.trigger(QSTORE_EVENT_ACTIVITY_PAUSE);
};

// 客户端回调：用户按下返回键
var closeEvent = $.Event(QSTORE_EVENT_ACTIVITY_CLOSE);
window.onBackKeyDown = function() {
    $evtEntity.trigger(closeEvent);

    if (!closeEvent.isDefaultPrevented()) {
        qStore.cmd('setOnBackKeyDownListenner', 0);
        setTimeout(function(){
            qStore.cmd('close');
        }, 10);
    }

    // 每次按下返回键，需要创建一个新的事件实例
    closeEvent = $.Event(QSTORE_EVENT_ACTIVITY_CLOSE);
};

// 激活activity resume时的回调函数
var enableResumeCallback = function() {
    qStore.cmd('setResumePauseLinnersenr', 1);
};

// 激活监听物理返回键功能
var enableBackkeydownCallback = function() {
    qStore.cmd('setOnBackKeyDownListenner', 1);
};

// 打开客户端回调
var enableClientCallback = function(evtType) {
    // 窗口被激活时
    if (evtType == QSTORE_EVENT_ACTIVITY_RESUME) {
        enableResumeCallback();
    }
    // 物理返回键按下时
    else if (evtType == QSTORE_EVENT_ACTIVITY_CLOSE) {
        enableBackkeydownCallback();
    }
};

event.trigger = function(evtType, data) {
    return $evtEntity.trigger(evtType, data);
};

event.off = function(evtType) {
    return $evtEntity.off.apply($evtEntity, arguments);
};

event.on = function(evtType) {
    enableClientCallback(evtType);

    return $evtEntity.on.apply($evtEntity, arguments);
};

event.one = function(evtType) {
    enableClientCallback(evtType);

    return $evtEntity.one.apply($evtEntity, arguments);
};

// 将event方法挂载到qStore上
$.extend(qStore, event);

// 页面中可能通过点击链接导致页面进行了跳转
// 如果没有关闭setOnBackKeyDownListenner， 返回按钮将失效
// todo: 这个地方可以手工触发onBackKeyDown();
$(document).on('click', 'a', function(evt){
    var docHref = location.href.replace(/#.*$/i, '');
    var linkHref = this.href.replace(/#.*$/i, '');

    if (!evt.isDefaultPrevented() && docHref != linkHref) {
        // 忽略linkHref为javascript:之类的情况
        if (/^https?:/i.test(linkHref)) {
            qStore.cmd('setOnBackKeyDownListenner', 0);
        }
    }
});

})(qStore.event = {}, qStore);

/**
 * @file App状态管理
 *
 */
;(function(qStore){

var appData = {};       // app信息
var notInstalledPackage = {};   // 已下载但未安装的包
var installedPackage = {};  // 本地已安装的包

// 状态码对应的下一步操作
// 如：
// 192实际上是下载中的状态，这时候的需要进入可暂停状态
// 193表示已暂停，这时候需要进入继续下载状态
var actionList = {
    '0'     : 'download',
    '490'   : 'download',  // 客户端卸载
  
    '190'   : 'waiting',
    '191'   : 'waiting',
    '196'   : 'waiting',
   
    '197'   : 'installing', // INSTALLING_MERGE
    '198'   : 'installing', // INSTALLING_CHECK_MD5
    '199'   : 'installing', // INSTALLING_CHECK_SAFE
    '3000'  : 'installing',
    // '3000' : 'install', // 下载完成后，取消安装
 
    '1'     : 'open',
    '189'   : 'downloading',
    '192'   : 'pause',
    '193'   : 'resume',
    '200'   : 'install',
    '10240' : 'update',
    '10495' : 'nonet'
};

var statusLabel = {
    'download'      : '下载',
    'update'        : '升级',
    'open'          : '打开',
    'pause'         : '暂停',
    'resume'        : '继续',
    'install'       : '安装',
    'downloading'   : '下载中',
    'installing'    : '安装中',
    'waiting'       : '等待中',
    'nonet'         : '等待中',
};

// 下载必须项
var downloadRequiredFields = [
   'pname', 'soft_id', 'soft_name', 'logo_url', 'download_urls',
   'version_code', 'apk_sizes', 'signature_md5s', 'apk_md5s', 'type', 'baike_name',

   'is_g','package_count'
];

var fixDataForDownload = function(source) {
    var transforms = {
        'pname' : 'apkid',
        'soft_name' : 'name',
        'download_urls' : 'down_url',
        'signature_md5s' : 'signature_md5',
        'apk_sizes' : 'size',
        'apk_md5s' : 'apk_md5'
    };

    for (var old in transforms) if (source[old]) {
        source[transforms[old]] = source[old];

        delete source[old];
    }

    return source;
};

// 是否支持暂停
var supportPause = false;

var PackageMgr = {
    init : function() {
        supportPause = qStore.support.pause();

        // 通知客户端需要监听安装进度
        qStore.cmd('addDownloadListenner');

        // 通知客户端需要监听安装包/移除包事件
        qStore.cmd('setInstallReceiver', 1);

        // 1. 获取本地已安装的app列表
        qStore.cmd('getInstatllApp', 'setAppStatus'); 

        // 2. 获取本地已下载未安装的app列表
        this._getNotInstalledPackage();
    },

    /**
     * 获取本地已下载未安装的包列表
     *
     * @param {string} apkid, 可选，包名
     */
    getLocalPackage : function(apkid) {
        if (apkid) {
            return notInstalledPackage[apkid];
        }
        
        return notInstalledPackage;
    },

    getInstalledPackage : function(apkid) {
        if (apkid) {
            return installedPackage[apkid];
        }

        return installedPackage;
    },

    /**
     * 获取已经下载但是还没有安装的应用
     * 
     * getDownloadApp返回的数据格式:
     * '[{"downPath":"\/storage\/sdcard0\/360Download\/jp.shade.DGunsSP-1375150171115.apk",
     *   "versionCode":20,
     *   "id" : xxxx,
     *   "pkgName":"jp.shade.DGunsSP"},
     *   {"downPath":"\/storage\/sdcard0\/360Download\/com.chaozh.iReaderFree-1375171277176.apk",
     *   "versionCode":55,
     *   "pkgName":"com.chaozh.iReaderFree"
     * }]'
     */
    _getNotInstalledPackage : function() {
        var pkgs = JSON.parse(qStore.cmd('getDownloadApp') || '[]');

        for (var i = 0, len = pkgs.length; i < len; i++) {
            notInstalledPackage[pkgs[i].pkgName] = pkgs[i];
        }

        return notInstalledPackage;
    },

    _setInstalledPackage : function(clientData) {
        // clientData = {
        //  com.android.dreams.phototable: "19"
        //  com.android.email: "500064"
        //  com.android.exchange: "500064"
        //  com.android.externalstorage: "19"
        //  com.android.galaxy4: "1"
        //  com.android.gallery3d: "40030"
        // }

        installedPackage = clientData;
    },

    updateLocalPackageInfo : function(action, apkid) {
        // 安装成功
        if (action == 'added') {
            installedPackage[apkid] = (
                (appData[apkid] || {}).version_code ||
                installedPackage[apkid] || 
                Infinity
            );

            delete notInstalledPackage[apkid];
        } 
        // 卸载
        else if (action == 'removed') {
            delete notInstalledPackage[apkid];
        }
    },

    getButtonLabel : function(status) {
        return statusLabel[status] || '下载';
    },

    // 获取状态码对应的动作
    getAction : function(statusCode) {
        // 下载中
        if (statusCode == '192') {
            return supportPause ? 'pause' : 'downloading';
        }

        return actionList[statusCode] || 'download';
    },

    // 是否已安装
    hasInstalled : function(apkid) {
        return !!installedPackage[apkid];
    },

    // 是否已下载(未安装)
    hasDownloaded : function(apkid) {
        return !!notInstalledPackage[apkid];
    },

    // 获取apk状态，只关注[已安装|已下载|未下载|可升级]
    getAppStatus : function(apkid, curVersionCode) {
        curVersionCode = curVersionCode || -1;

        // 已安装
        if (this.hasInstalled(apkid)) {
            // 可升级
            if (installedPackage[apkid] < curVersionCode) {
                return 10240;
            }

            return 1;
        }

        // 已下载未安装

        // 有这样一种情况需要考虑:
        // 通过其他方式（非本页面)下载一个较低版本的包
        // 客户端的处理逻辑是显示为下载
        var localPackage = notInstalledPackage[apkid];
        if (localPackage) {
            if (localPackage.versionCode && localPackage.versionCode < curVersionCode) {
                return 0;
            }

            // 已部分下载
            var status = localPackage.status;
            if (status) {
                if (status == '193' || status == '196') {
                    return 193;
                }
            }

            return 200;
        }

        // 未下载
        return 0;
    },

    clearAppData : function(apkid) {
        appData[apkid] && (appData[apkid] = null);
    },

    addAppData : function(data) {
        if ($.type(data) == 'array') {
            for (var i = 0, len = data.length; i < len; i++) {
                add(data[i]);
            }
        } else {
            add(data);
        }

        return;

        function add(data) {
            if (!data || !data.apkid) {
                return;
            }

            appData[data.apkid] = appData[data.soft_id] = data;
        }
    },

    getAppData : function(keys, fields, isDownload) {
        var deferred = $.Deferred();

        if (isDownload && appData[keys]) {
            deferred.resolve(appData[keys]);
        }

        else {
            // var url = 'http://openbox.mobilem.360.cn/index/getSoftInfoByIdsAccordingToFields/sids/' + sid +'/fields/';
            var controller, path, url;

            if ($.type(keys) == 'string') {
                keys = keys.split(/\s*,\s*/i);
            }

            // 传递的是sid
            if (/^\d+$/i.test(keys[0])) {
                controller = 'getSoftInfoByIdsAccordingToFields/sids/';
            } else {
                controller = 'getSoftInfoByPnamesAccordingToFields/pnames/';
            }

            if ($.type(fields) == 'string') {
                fields = fields.split(/\s*,\s*/i);
            }
            fields = fields || downloadRequiredFields;

            path = '//openbox.mobilem.360.cn/index/' + controller;
            url = qStore.util.getProtocol() + path + keys.join('|') + '/fields/' + fields.join('|');

            $.ajax({
                url : url,
                dataType : 'jsonp',
                success : function(res) {
                    var list = [];
                    for (var i in res) if (res.hasOwnProperty(i)) {
                        res[i] = fixDataForDownload(res[i]);
                        list.push(res[i]);
                    }

                    // 如果是用户触发的下载行为，则缓存数据
                    if (isDownload) {
                        appData[list[0].apkid] = appData[list[0].soft_id] = list[0];

                        deferred.resolve(list[0]);
                    } else {
                        deferred.resolve(list, res);
                    }
                }
            });
        }

        return deferred.promise();
    },

    getCachedAppData : function() {
        return appData;
    },

    getAppStatusLabel : function() {
        return statusLabel;
    }
};

qStore.getPackageMgr = function() {
    return PackageMgr;
};

// 下载相关事件
window.QSTORE_EVENT_APP_DOWNLOADING = 'qstore-app-downloading';
window.QSTORE_EVENT_APP_INSTALL_FINISH = 'qstore-app-install-finish';
window.QSTORE_EVENT_APP_DOWNLOAD_FINISH = 'qstore-app-download-finish';
window.QSTORE_EVENT_APP_CHANGE = 'qstore-app-change'; // 新增|删除包


// ==注册客户端回调函数==

// 客户端回调：下载进度通知
// todo: 需要考虑秒装失败的情况

var oldUADP = window.updateAppDownloadProgress;
var prevStatus = {};
window.updateAppDownloadProgress = function(data) {
    // data = { 
    //  "com.ledo.bxzw.qihoo360" : {
    //      id: "com.ledo.bxzw.qihoo360"
    //      progress: "3"
    //      savePath: "/storage/emulated/0/360Download/com.ledo.bxzw.qihoo36013.apk"
    //      size: "249670610"
    //      speed: "6.42M/s"
    //      status: "192"
    //      version_code: "13"
    //  }
    // }
    oldUADP && oldUADP(data);

    for (var apkid in data) if (data.hasOwnProperty(apkid)) {
        var pkg = data[apkid];

        // 192[下载中] -> 200[下载完成] -> 3000[安装中] -> 200[取消安装]
        // 但是现在5.0 是直接从 192 跳到 3000，取消安装也不会触发200

        // 开始安装
        if (pkg.status == '3000') {
            // 3000会触发多次
            if (prevStatus[apkid] != '3000') {
                // 回调下载完成事件处理器
                qStore.event.trigger(QSTORE_EVENT_APP_DOWNLOAD_FINISH, [pkg]);

                // 5.0在安装界面上点击取消，客户端不会通知结果
                // 因此进行手工检测
                qStore.one(QSTORE_EVENT_ACTIVITY_RESUME, function(evt){
                    // 延迟查询，让已安装的apkid添加到installedPackage中
                    setTimeout(function(){
                        // 以下2种情况放弃检测:
                        // 1. 老版本或者后续新版点击取消时抛出200;
                        // 2. 安装成功
                        if (prevStatus[apkid] == '200' || prevStatus[apkid] == '1') {
                            return;
                        }

                        if (!PackageMgr.hasInstalled(apkid)) {
                            data[apkid]['status'] = '200';
                            data[apkid]['isManualProgress'] = 1;
                            window.updateAppDownloadProgress(data);
                        }
                    }, 10);
                });
            }
        }
        
        // 下载完成时，将该APP信息保存至notInstalledPackage
        else if (pkg.status == '200') {
            notInstalledPackage[apkid] = pkg;

            // 回调下载完成事件处理器
            if (!pkg.isManualProgress) {
                qStore.event.trigger(QSTORE_EVENT_APP_DOWNLOAD_FINISH, [pkg]);  
            }
        }
        // 安装完成时
        // 5.0版本不再触发这个状态
        else if (pkg.status == '1') {
            installedPackage[apkid] = (
                pkg.version_code || 
                (appData[apkid] || {}).version_code ||
                Infinity
            );

            delete notInstalledPackage[apkid];

            qStore.event.trigger(QSTORE_EVENT_APP_INSTALL_FINISH, [pkg]);
        }

        prevStatus[apkid] = pkg.status;
    }

    qStore.event.trigger(QSTORE_EVENT_APP_DOWNLOADING, [data]);
};

// 客户端回调：安装完成或者卸载回调[added:安装成功|removed：已卸载]
// data = {pkgname:'xxx', action:['added'|'removed']}
var oldAIA = window.AppInstallAction;
window.AppInstallAction = function(data) {
    oldAIA && oldAIA(data);

    var apkid = data.pkgname;

    PackageMgr.updateLocalPackageInfo(data.action, apkid);

    // 新版本安装完成后，不再触发status='1'状态
    // 这里我们手工触发下
    if (data.action == 'added') {
        var progressData = {};

        progressData[apkid] = notInstalledPackage[apkid] || {};
        progressData[apkid]['status'] = '1';
        window.updateAppDownloadProgress(progressData);
    }

    qStore.event.trigger(QSTORE_EVENT_APP_CHANGE, [data]);
};

// 客户端回调：删除包
// 分两种情况，下载中删除和安装后删除，只处理下载中删除情况
// todo: 这个地方可能会产生bug, 因为移除的可能是上次已安装但是未删除的包
var oldremovepackageHandler = window.AndroidWebview_removePackage;
window.AndroidWebview_removePackage = function(apkid, action) {
    oldremovepackageHandler && oldremovepackageHandler(apkid);
    
    // 5.0 已经删除 isInstalled
    action = (
        qStore.cmd('isInstalled', apkid) == 'true' ?
        'added' : 'removed'
    );

    PackageMgr.updateLocalPackageInfo(action, apkid);

    qStore.event.trigger(QSTORE_EVENT_APP_CHANGE, [{
        action : action,
        pkgname : apkid
    }]);
};

// 客户端回调：获取已安装的app列表
var oldSetAppStatus = window.setAppStatus;
window.setAppStatus = function(data) {
    oldSetAppStatus && oldSetAppStatus(data);

    PackageMgr._setInstalledPackage(data);
};

qStore.ready(function(){
    PackageMgr.init();
});

})(window.qStore);

/**
 * @file 127下载
 *
 * 参考:
 * http://test1.baohe.mobilem.360.cn/html/test/wifi_client.html?360appstore=1
 */
(function(qStore){

var getSign = function(key, callback) {
    var deferred = $.Deferred();
    
    $.ajax({
        url : 'http://openbox.mobilem.360.cn/qing/spiritkey?key=' + encodeURIComponent(key),
        dataType : "jsonp",
        success : function(res) {
            callback && callback(res.sign);
            deferred.resolve(res.sign);
        }
    });

    return deferred.promise();
};

var Spirit = {
    download : function(app, callback) {
        return getSign(app.down_url).then(function(sign){
            var data = {
                url : app.down_url,
                sign : sign,
                logo : app.logo_url,
                name : app.name
            };

            var url = 'http://i.qstore.org:38517/in?';

            return $.ajax({
                url : url,
                data : data,
                dataType : 'jsonp',
                success : function() {
                    callback && callback(true);
                }
            });
        });
    },

    //  注：只可打开 360 so qihoo mgamer 域下页面
    openPage : function(url, callback) {
        callback = callback || function() {};

        $.ajax({
            url : "http://i.qstore.org:38517/openPage?needCookie=1&url=" + encodeURIComponent(url) + "&_=" + Math.random(),
            dataType : "jsonp",
            success : function(data){
                callback(true);
            },
            error : function(e){
                callback();
            }
        });
    },

    /**
    * String packageName = params.get("packageName");
    * String sign = params.get("sign");
    * String callback = params.get("callback");
    */
    hasInstalled : function(apkid, callback) {
        return getSign(apkid).then(function(sign){
            return $.ajax({
                url : 'http://i.qstore.org:38517/isAppInstalled',
                data : {
                    packageName : apkid,
                    sign : sign
                },
                dataType : 'jsonp',
                success : function(data) {
                    callback && callback(data.isInstalled);
                },

                error : function() {
                    callback && callback(false);
                }
            });
        });
    },

    getClientInfo : function() {
        return qStore.env._127_clientInfo || {};
    }
};

qStore.spirit = Spirit;

})(window.qStore);
/**
 * @file 下载功能
 */
(function(app, qStore){

// 是否是CP提供的电子书
var isCPBook = function(appData) {
    return (
        appData.type == "ebook"   && 
        appData.cpbook_id         && 
        appData.cpbook_detailurl  && 
        window.AndroidWebview     &&
        AndroidWebview.openCPBook
    );
};

var plugin = qStore.getDownloadPlugin();
var packageMgr = qStore.getPackageMgr();
var event = qStore.event;

var download = function(appData) {
    if (isCPBook(appData)) {
        qStore.cmd('openCPBook', appData);
    } else {
        qStore.cmd('downloadApp', appData);
    }
};

/**
 * 下载应用
 * 
 * @param {json|apkid} app
 * @return null
 */
app.download = function(appData) {
    var type = $.type(appData);
    if (type == 'string' || type == 'number') {
        app.downloadFromId(appData);

        return;
    }

    var downloadable = plugin.downloadable(appData);
    if (downloadable === false) {
        return;
    }
    
    // 延时下载
    var delayTime = (
        typeof downloadable == 'number' ?
        downloadable : 30
    );
    setTimeout(function(){
        var customData = plugin.getAppData($.extend({}, appData));

        if ($.type(customData) != 'object' || $.isPlainObject(customData)) {
            customData = appData;
        }

        download(customData);

        event.trigger('qstore-app-download', [customData]);
    }, delayTime);
};

/**
 * 下载应用
 * 
 * @param {string} apkid|sid
 * @return null
 */
app.downloadFromId = function(id) {
    packageMgr.getAppData(id, null, true).then(function(appData){
        app.download(appData);  
    });
};

/**
 * 打开应用                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             
 *
 * @return null
 */
app.open = function(appData) {
    if ($.type(appData) == 'string') {
        return packageMgr.getAppData(appData, null, true).then(function(app){
            qStore.app.open(app);
        });
    }

    var delay = plugin.openable(appData);
    
    // 返回false, 不打开
    if (delay === false) {
        return;
    }

    // 返回数字， 延时打开
    setTimeout(function(){
        event.trigger('qstore-app-open', [appData]);

        if (isCPBook(appData)) {
            qStore.cmd('openCPBook', appData);
        } else {
            qStore.cmd('launchApp', {
                apkid : appData.apkid
            });
        }
    }, typeof delay == "number" ? delay : 0);
};

/**
 * 停止下载
 *
 * @return null
 */
app.pause = function(appData) {
    qStore.cmd('pauseDownloadApp', appData.apkid);

    event.trigger('qstore-app-pause', [appData]);
};

/**
 * 恢复下载
 *
 * @return null
 */
app.resume = function(appData) {
    this.download(appData);

    event.trigger('qstore-app-resume', [appData]);
};

/**
 * 安装
 *
 * @return null
 */
app.install = function(appData) {
    var data = packageMgr.getLocalPackage(appData.apkid);

    if (!data || qStore.cmd('installAppFormId', data.id) == '-1') {
        qStore.util.showMessage('安装失败，请您重新下载');
        
        // 手动触发安装包移除事件
        window.AppInstallAction({
            action : 'removed',
            pkgname : appData.apkid
        });
    }

    event.trigger('qstore-app-install', [appData]);
};

/**
 * 跳转至详情页
 *
 * @param {apkid} 包名
 */
app.gotoDetail = function(apkid) {
    packageMgr.getAppData(apkid, null, true).then(function(appData) {
        event.trigger('qstore-app-to-detail', [appData]);

        qStore.cmd(
            'gotoPage', 
            $.extend({'page' : 'detail'}, appData)
        );
    });
};

/**
 * 查询app状态
 *
 * @return {number} 0-未下载 1-已安装 10240-可升级 200-已下载
 */
app.getStatus = function() {
    return packageMgr.getAppStatus.apply(packageMgr, arguments);
};

/**
 * 添加app数据
 *
 */
app.addData = function(data) {
    return packageMgr.addAppData(data);
};

/**
 * 获取app数据
 *
 * @param keys {string|array} 
 * keys 可以是 "sid1,sid2" 或者 "pkgid1, pkgid2" 或者 ["pkgid1", "pkgid2"]
 * 如果传递的是单个sid或者pkgid， 则返回的数据中，也只会有单个{}, 否则，返回的数据是[]
 *
 * @return {promise}
 * 
 */
app.getData = function(keys, fields) {
    var isArray = (
        $.type(keys) == 'array' || 
        $.type(keys) == 'string' && keys.split(',').length > 1
    );

    return packageMgr.getAppData(keys, fields).then(function(list, map){
        return isArray ? list : list[0];
    });
};

})((qStore.app = {}), qStore);

/**
 * @file 页面下载交互处理
 *
 */
;(function(qStore){
    
var plugin = qStore.getDownloadPlugin();
var packageMgr = qStore.getPackageMgr();
var util = qStore.util;
var domNodeCache = {}; // 保存dom节点引用

var getClassObj = function($el) {
    var clsObj = {};

    ($el.attr('class') || '').replace(/([^\s]+)/g, function(all, cn){
        clsObj[cn] = 1;
    });

    return clsObj;
};

// Object.keys
var keys = Object.keys || function(obj) {
    var r = [];

    for (var k in obj) if (obj.hasOwnProperty(k)) {
        r.push(k);
    }

    return r;
};

var appStatusName = packageMgr.getAppStatusLabel();
var rbtnStatusClass = new RegExp("(?:^|\\s+)is-(" + keys(appStatusName).join('|') + ")(?:\\s+|$)", 'ig');
// console.log(rbtnStatusClass.source);
// (?:^|\s+)is-(download|update|open|pause|resume|install|downloading|installing|waiting|nonet)(?:\s+|$)

var web = {
    init : function() {
        this.appBtnList = (
            document.getElementsByClassName ? 
            document.getElementsByClassName('js-app-btn') : []
        );

        this.bindEvents();
    },

    downloadInZhushou : function(app, clsObj, clsStr) {
        // 下载
        // 如果.js-app-btn没有.is-[download...], 也开启下载
        if (
            clsObj['is-download'] || 
            clsObj['is-resume'] || 
            clsObj['is-update'] ||
            !rbtnStatusClass.test(clsStr)
        ) {
            qStore.app.download(app);
        }

        // 打开 
        else if (clsObj['is-open']) {
            qStore.app.open(app);
        }

        // 暂停
        else if (clsObj['is-pause']) {
            qStore.app.pause(app);
        }
        
        // 安装
        else if (clsObj['is-install']) {
            qStore.app.install(app);
        }
    },

    bindEvents : function() {
        var $doc = $(document);
        var _this = this;

        $doc.on('click', '.js-app-btn', function(evt) {
            var $trigger = $(evt.target);
            var $appItem = $trigger.closest('.js-app-item');
            var $appBtn = $(this);
            var apkid, promise;

            evt.preventDefault();

            apkid = $appItem.data('apkid') || $appBtn.data('apkid');
            if (!apkid) {
                return qStore.util.showMessage('未找到应用包名');
            }

            // todo: 如果是打开APP， 则不需要去获取新的数据
            promise = packageMgr.getAppData(apkid, null, true);

            // 助手下载
            if (qStore.env.is_zhushou) {
                promise.then(function(app){
                    _this.downloadInZhushou(app, getClassObj($appBtn), $appBtn.attr('class'));
                });
            }

            // 127下载
            else if (qStore.env.isRPCWorking) {
                promise.then(function(app){
                    qStore.trigger('web-download-start', [app]);

                    qStore.spirit.download(app);
                });
            }

            // 微信下载
            // todo: QQ ? 
            else if (qStore.env.is_weixin || qStore.env.is_qq) {
                // do nothing
                promise.then(function(app){
                    qStore.trigger('web-download-failed', [app]);
                });
            }
            // todo: 检测到是web环境，需要处理apk下载
            // 如果$appBtn的href不是apk，则自动开启window.location进行下载
            else {
                var apkUrl = $appBtn[0].href;
                if (!/\.apk$/i.test(apkUrl)) {
                    promise.then(function(app){
                        window.location.href = app.down_url;
                    });
                } else {
                    window.location.href = apkUrl;
                }
            }
        });

        $doc.on('click', '.js-app-item', function(evt){
            var $target = $(evt.target);
            var $closestA = $target.closest('a');

            if ($(this).is('.js-app-btn')) {
                return;
            }

            // 以下2种情况跳转至详情页
            // 1. 点击的不是A或者不是A的子节点
            // 2. 或者 js-app-item 本身是一个A链接
            if ($closestA.length == 0 || $closestA[0] == this) {
                var apkid = $(this).data('apkid');
                if (!apkid) {
                    apkid = $(this).find('.js-app-btn').data('apkid');
                }

                if (apkid) {
                    qStore.app.gotoDetail(apkid);
                } else {
                    window.console && console.log('未找到APKID');
                }
                

                evt.preventDefault();
            }
        });

        $doc.on('click', '.js-app-link', function(evt){
            if (qStore.env.is_zhushou) {
                var href = $(this)[0].href || $(this).data('href') || '';
                
                if (href.length > 0) {
                    qStore.util.openUrl(href);
                }

                evt.preventDefault();
            }
        });

        // 下载中
        // todo: 缓存找到的dom节点
        // todo: 通过class="app-pkgname" 提升查找速度
        // https://www.nczonline.net/blog/2010/09/28/why-is-getelementsbytagname-faster-that-queryselectorall/
        // getElementsByClassName() 返回的也是live NodeLists
        qStore.event.on(QSTORE_EVENT_APP_DOWNLOADING, function(evt, data){
            // data = { 
            //  "com.ledo.bxzw.qihoo360" : {
            //      id: "com.ledo.bxzw.qihoo360"
            //      progress: "3"
            //      savePath: "/storage/emulated/0/360Download/com.ledo.bxzw.qihoo36013.apk"
            //      size: "249670610"
            //      speed: "6.42M/s"
            //      status: "192"
            //      version_code: "13"
            //  }
            // }
            for (var apkid in data) if (data.hasOwnProperty(apkid)) {
                _this.updateStatus(apkid, data[apkid]);
            }
        });

        // 本地[安装|卸载]包
        qStore.event.on(QSTORE_EVENT_APP_CHANGE, function(evt, data) {
            _this.updateStatus(data.pkgname, {
                'progress' : '0',
                'status' : data.action == 'removed' ? '490' : '1'
            });
        });
    },

    updateStatus : function(apkid, data) {
        var action = packageMgr.getAction(data.status);
        
        // 过滤掉[等待中]
        if (action == 'waiting') {
            return;
        }

        var data = {
            apkid: apkid,
            version : data.version_code,
            action : action,
            progress : data.progress,
            speed : data.speed
        };

        var buttonHTML = (
            plugin.getButtonHTML(action, data) || 
            this.getButtonHTML(action, data)
        );

        var buttons = this.getButtonsByApkid(apkid);
        var _this = this;
        $.each(buttons, function(index, $btn){
            _this.setButtonHTML($btn, data, buttonHTML);
        });
    },

    setButtonHTML : function($btn, data, html) {
        var action = data.action;
        var html = html || plugin.getButtonHTML(action, data) || this.getButtonHTML(action, data);

        var clsName = $btn.attr('class');

        rbtnStatusClass.lastIndex = 0;
        if (!rbtnStatusClass.test(clsName)){
            clsName += ' is-' + action;
        } 

        else {
            clsName = clsName.replace(rbtnStatusClass, function(all, cls){
                return ' is-' + (appStatusName[cls] ? action : cls) + ' ';
            }).replace(/^\s+/i, '');
        }

        $btn.html(html).attr('class', $.trim(clsName));
    },

    // 全局检测页面状态
    checkAppStatus : function() {
        var _this = this;
        var installedApk = {};

        $('.js-app-btn').each(function(){
            var $btn = $(this);
            var $item = $btn.closest('.js-app-item');
            var apkid = $item.data('apkid') || $btn.data('apkid');
            var version = $item.data('ver') || $btn.data('ver') || -1;
            var status = packageMgr.getAppStatus(apkid, version);

            if (status > 0) {
                // 页面中没有指定版本号
                if (version == -1 && status == 1) {
                    installedApk[apkid] = 1;
                }

                _this.setButtonHTML($btn, {
                    apkid : apkid,
                    version : version,
                    action : packageMgr.getAction(status),
                    progress : 0
                });
            }
        });

        /*
        var apkidList = keys(installedApk);
        packageMgr.getAppData(apkidList, ['version_code']).then(function(res){
            console.log(res);
        });
        */
        // todo: 检测升级
    },

    getButtonsByApkid : function(targetApkid) {
        var buttons = [];
        var find = function($el) {
            var apkid = $el.data('apkid') || $el.closest('.js-app-item').data('apkid');
            
            if (apkid == targetApkid) {
                buttons.push($el);
            }
        };

        // appBtnList 是一个引用，dom树变化时会由浏览器自动更新
        var len = this.appBtnList.length;
        if (len > 0) {
            for (var i = 0; i < len; i++) {
                find($(this.appBtnList[i]));
            }
        } else {
            $('.js-app-btn').each(function(i, el){
                find($(el));
            });
        }

        return buttons;
    },

    getButtonHTML : function(action, data) {
        var progress = data.progress;
        var label = (
            plugin.getButtonLabel(action, data) || 
            packageMgr.getButtonLabel(action, data)
        );

        return [
            '<span class="_icon"></span>',
            '<span class="_progress o-progress">',
                '<i class="_bar" style="width:' + (progress || 0) + '%;"></i>',
            '</span>',
            '<span class="_label">' + label + '</span>',
        ].join('');
    }
};

web.init();

// 客户端ready后才检测状态
qStore.ready(function(){
    // domReady 后才检测页面状态
    $(function(){
        web.checkAppStatus(); 
    });
});

qStore.web = web;

})(window.qStore);
/**
 * @file 分享功能
 *
 * 支持微信，会自动加载微信的JS API文件
 */
(function(share, qStore){

var weixinJsRequested = false;
var weixinJSDelay = new qStore.lib.Delay();

var weixinConfigDeferred = $.Deferred();
var weixinConfigPromise = weixinConfigDeferred.promise();

var fireWeixinJSReady = function() {
    weixinJSDelay.fireReady();
};

var shareData;

window.QSTORE_EVENT_SHARE_FINISH = 'qstore-share-finish';
var fireShareFinishEvent = function(result) {
    qStore.trigger(QSTORE_EVENT_SHARE_FINISH, [result]);
};
var setupCallback = function(callback) {
    // 每次传递新的callback， 都需要废弃上次绑定
    qStore.off(QSTORE_EVENT_SHARE_FINISH);

    qStore.on(QSTORE_EVENT_SHARE_FINISH, function(evt, result){
        callback(result);
    });
};

var WebShare = {
    run : function() {
        // 微博分享
        if (!qStore.env.is_weixin) {
            // shareDeferred.resolve(true);
            fireShareFinishEvent(true);

            setTimeout(function(){
                location.href = (
                    'http://service.weibo.com/share/share.php?title=' + shareData.weixinTitle + 
                    '&url=' + shareData.weixinUrl + 
                    '&pic=' + shareData.weiboImg + 
                    '&appkey=4051837633&searchPic=false'
                );
            }, 30);
        }
    },

    setWXShareCallback : function() {
        wx.onMenuShareTimeline({
            title: shareData.weixin, // 分享标题
            link: shareData.weixinUrl, // 分享链接
            imgUrl: shareData.weixinThumbnailUrl, // 分享图标

            // 用户确认分享后执行的回调函数
            success: function() {
                fireShareFinishEvent(true);
            },

            // 用户取消分享后执行的回调函数
            cancel: function() {
                fireShareFinishEvent(false);
            }
        });

        wx.onMenuShareAppMessage({
            title: shareData.weixinTitle,
            desc: shareData.weixin,
            link: shareData.weixinUrl,
            imgUrl: shareData.weixinThumbnailUrl,
            trigger: function(res) {
                //alert('用户点击发送给朋友');
            },
            // 用户确认分享后执行的回调函数
            success: function() {
                fireShareFinishEvent(true);
            },

            // 用户取消分享后执行的回调函数
            cancel: function() {
                fireShareFinishEvent(false);
            },

            fail: function(res) {
                //alert(JSON.stringify(res));
                fireShareFinishEvent(false);
            }
        });
    },
    
    getWXConfig : function() {
        $.ajax({
            url: 'http://huodong.mobilem.360.cn/weixin/getWeixinJsConfig',
            data: {
                format: 'json',
                url: location.href.split('#')[0],
            },
            dataType: 'jsonp',

            //  默认返回的result :{"status":1,"msg":"success.","data":{"timestamp":1421904851,"nonceStr":"9d5175e364885f565728c762ecf5dd8c","signature":"095ed0fecff181836830b4a6c597bcfee2ec3717"}}
            success: function(result) {
                weixinJSDelay.ready(function(){
                    WebShare.setupWxConfig(result.data);

                    weixinConfigDeferred.resolve();
                });
            }
        });
    },

    // 加载微信js
    loadWXAPI : function(src) {
        if (window.wx && wx.config) {
            return fireWeixinJSReady();
        }

        if (weixinJsRequested) return;

        weixinJsRequested = true;
        src = qStore.util.getProtocol() + '//res.wx.qq.com/open/js/jweixin-1.0.0.js';

        var script = document.createElement('script');
        script.onload = fireWeixinJSReady;
        script.onreadystatechange = function() {
            if (/loaded|complete/i.test(this.readyState)) {
                fireWeixinJSReady();
            }
        };
        script.src = src;
        $(document.body).append(script);
    },

    init : function() {
        if (qStore.env.is_weixin) {
            this.loadWXAPI();
            this.getWXConfig();
        }
    },

    setupWxConfig : function(config) {
        wx.config({
            debug: false,
            appId: config.appId,
            timestamp: config.timestamp,
            nonceStr: config.nonceStr,
            signature: config.signature,
            jsApiList: [
                'checkJsApi',
                'onMenuShareTimeline',
                'onMenuShareAppMessage',
                'onMenuShareQQ',
                'onMenuShareWeibo',
                'hideMenuItems',
                'showMenuItems',
                'hideAllNonBaseMenuItem',
                'showAllNonBaseMenuItem',
                'scanQRCode',
                'startRecord',
                'stopRecord',
                'onVoiceRecordEnd',
                'translateVoice',
                'chooseImage',
                'previewImage',
                'uploadImage',
                'downloadImage'
            ]
        });
    }
};

WebShare.init();

/**
 * 设置分享数据 
 *
 * @param  {Object} options 分享数据对象
 * @key title 分享标题
 * @key link 分享页面地址
 * @key content 分享内容
 * @key weibo 微博文案
 * @key logo 分享的 ICON 图片
 * @key weiboImg 微博分享图
 * @key localPic 本地图片路径
 * @key extra 其他参数，比如是否显示qq，显示微博等
 * 
 * 如下均为客户端默认设置：
 * options.extra = {
 *    showSms : true,
 *    showMore : true,
 *    showQQ : true,
 *    showQQZone : true,
 *    showSina : true,
 *    showTimeLine : true,
 *    showWxFriend : true
 * }
 */
share.setData = function(options, callback) {
    var shareUrl = options.link || location.href;
    var title = options.title || document.title;
    var content = options.content || document.title;
    var logo = options.logo || 'http://p19.qhimg.com/t01b792441769dbca78.png'; // 默认为助手logo
    
    // 助手分享
    var param = {
        'default' : options.weibo || (content + ' ' + shareUrl),
        weixin : content,
        weixinUrl : shareUrl,
        weixinTitle : title,
        weixinThumbnailUrl : logo,
        localPic: options.localPic || '',
        weiboImg: options.weiboImg || logo || '',
        needMonitor: true
    };

    if (options.extra) {
        param = $.extend(param, options.extra);
    }

    shareData = param;

    weixinConfigPromise.then(function(){
        wx.ready(function(){
            WebShare.setWXShareCallback();  
        });
    });

    callback && setupCallback(callback);
};

 /**
 * 分享接口 
 *
 * @param  {Object} options 分享数据对象
 * @param {function} callback 分享结果回调函数
 *
 * @return {Promise}
 */
share.run = function(options, callback) {
    if ($.type(options) == 'function') {
        callback = options;
        options = false;
    }

    // 尚未设置分享数据或者传递了新的数据
    if (!shareData || options) {
        this.setData(options || {});
    }

    callback && setupCallback(callback);

    // web分享
    if (!window.AndroidWebview) {
        WebShare.run(shareData);

        return;
    }
    
    window.AndroidWebview_onShareDone = function(r) {
        fireShareFinishEvent(r === 'true');
    };

    // 客户端弹出分享界面后，可能会影响当前页面JS执行
    setTimeout(function(){
        if (AndroidWebview.simpleShareToSNS) {
            AndroidWebview.simpleShareToSNS(JSON.stringify(shareData));
        } else {
            AndroidWebview.shareToSNS(JSON.stringify({
                imgUrl: shareData.weixinThumbnailUrl, 
                content: shareData.weixin
            }));
        }
    }, 10);
};

qStore.util.share = function() {
    return share.run.apply(share, arguments);
};

})((qStore.share = {}), window.qStore);